// Serial.cpp: implementation of the CSerial class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "GPS Simulator.h"
#include "Serial.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CSerial::CSerial()
{

}

CSerial::~CSerial()
{

}


LONG CSerial::Open(LPCTSTR lpszCOMPort, DWORD dwInQueue, DWORD dwOutQueue)
{

	m_lLastError = ERROR_SUCCESS;

	m_hFile = CreateFile(lpszCOMPort, 
						GENERIC_READ | GENERIC_WRITE,
						0, // exclusive access
						NULL, // no security
						OPEN_EXISTING,
						0, // no overlapped I/O
						NULL); // null template 

	
	if (m_hFile == INVALID_HANDLE_VALUE)
	{
		// Reset file handle
		m_hFile = 0;

		// Display error
		m_lLastError = ::GetLastError();
		_RPTF0(_CRT_WARN, "CSerial::Open - Unable to open port\n");
		return m_lLastError;
	}

	_ASSERTE(dwInQueue >= 16);
	_ASSERTE(dwOutQueue >= 16);

	if (!::SetupComm(m_hFile,dwInQueue,dwOutQueue))
	{
		// Display a warning
		long lLastError = ::GetLastError();
		_RPTF0(_CRT_WARN,"CSerial::Open - Unable to setup the COM-port\n");

		// Close the port
		Close();

		// Save last error from SetupComm
		m_lLastError = lLastError;
		return m_lLastError;	
	}	
	
	return m_lLastError;
}


LONG CSerial::Setup (EBaudrate eBaudrate, EDataBits eDataBits, EParity eParity, EStopBits eStopBits)
{
	
	m_lLastError = ERROR_SUCCESS;

	if (m_hFile == 0)
	{
		// Set the internal error code
		m_lLastError = ERROR_INVALID_HANDLE;

		// Issue an error and quit
		_RPTF0(_CRT_WARN,"CSerial::Setup - Device is not opened\n");
		return m_lLastError;
	}

	// Obtain the DCB structure for the device
	DCB dcb;
	if (!::GetCommState(m_hFile,&dcb))
	{
		// Obtain the error code
		m_lLastError = ::	GetLastError();

		// Display a warning
		_RPTF0(_CRT_WARN,"CSerial::Setup - Unable to obtain DCB information\n");
		return m_lLastError;
	}
	
	dcb.BaudRate = DWORD(eBaudrate);
	dcb.ByteSize = BYTE(eDataBits);
	dcb.Parity   = BYTE(eParity);
	dcb.StopBits = BYTE(eStopBits);

	// Determine if parity is used
	dcb.fParity  = (eParity != EParNone);
	dcb.fAbortOnError = TRUE;

	return m_lLastError;

	if (!::SetCommState(m_hFile,&dcb))
	{
		// Obtain the error code
		m_lLastError = ::GetLastError();

		// Display a warning
		_RPTF0(_CRT_WARN,"CSerial::Setup - Unable to set DCB information\n");
		return m_lLastError;
	}

	COMMTIMEOUTS m_CommTimeouts;

	if (!::GetCommTimeouts(m_hFile,&m_CommTimeouts))
	{
		// Obtain the error code
		m_lLastError = ::	GetLastError();

		// Display a warning
		_RPTF0(_CRT_WARN,"CSerial::Setup - Unable to obtain DCB information\n");
		return m_lLastError;
	}

	m_CommTimeouts.ReadIntervalTimeout = MAXWORD;
	m_CommTimeouts.ReadTotalTimeoutConstant = 1000;	//50;
	m_CommTimeouts.ReadTotalTimeoutMultiplier = 1000;	//10;
	m_CommTimeouts.WriteTotalTimeoutConstant = 1000;	//50;
	m_CommTimeouts.WriteTotalTimeoutMultiplier = 1000;	//10;

	if (!::SetCommTimeouts(m_hFile,&m_CommTimeouts))
	{
		// Obtain the error code
		m_lLastError = ::	GetLastError();

		// Display a warning
		_RPTF0(_CRT_WARN,"CSerial::Setup - Unable to obtain DCB information\n");
		return m_lLastError;
	}

	return m_lLastError;
	
}

LONG CSerial::Write (LPCSTR lpszData, DWORD *iBytesWritten)
{

	m_lLastError = ERROR_SUCCESS;

	DWORD dwWritten;
	if (iBytesWritten == 0)
	{
		iBytesWritten = &dwWritten;
	}

	// Reset the number of bytes written
	*iBytesWritten = 0;

	if (m_hFile == 0)
	{
		// Set the internal error code
		m_lLastError = ERROR_INVALID_HANDLE;

		// Issue an error and quit
		_RPTF0(_CRT_WARN,"CSerial::Write - Device is not opened\n");
		return m_lLastError;
	}

	if (!::WriteFile(m_hFile,lpszData,strlen(lpszData),iBytesWritten,NULL))
	{
		// Set the internal error code
		m_lLastError = ::GetLastError();

		// Issue an error and quit
		_RPTF0(_CRT_WARN,"CSerial::Write - Unable to write the data\n");
		return m_lLastError;
	}

	return m_lLastError;
}

LONG CSerial::Close()
{

	// Reset error state
	m_lLastError = ERROR_SUCCESS;

	// If the device is already closed,
	// then we don't need to do anything.
	if (m_hFile == 0)
	{
		// Display a warning
		_RPTF0(_CRT_WARN,"CSerial::Close - Method called when device is not open\n");
		return m_lLastError;
	}

	// Close COM port
	::CloseHandle(m_hFile);
	m_hFile = 0;

	// Return successful
	return m_lLastError;

}


CSerial::EPort CSerial::IsPortAvailable (LPCTSTR lpszDevice)
{
	// Try to open the device
	HANDLE hFile = ::CreateFile(lpszDevice, 
						   GENERIC_READ|GENERIC_WRITE, 
						   0, 
						   0, 
						   OPEN_EXISTING, 
						   0,
						   0);

	// Check if we could open the device
	if (hFile == INVALID_HANDLE_VALUE)
	{
		// Display error
		switch (::GetLastError())
		{
		case ERROR_FILE_NOT_FOUND:
			// The specified COM-port does not exist
			return EPortNotAvailable;

		case ERROR_ACCESS_DENIED:
			// The specified COM-port is in use
			return EPortInUse;

		default:
			// Something else is wrong
			return EPortUnknownError;
		}
	}

	// Close handle
	::CloseHandle(hFile);

	// Port is available
	return EPortAvailable;
}